library(Seurat)
library(ggplot2)
library(tidyverse)
library(fgsea)
library(gridExtra)
library(devtools)
library(DT)
require(corrplot)
library(clustree)
library(ggsignif)
library(ggpubr)
library(viridis)
library(plotly)
library(ggridges)
library(reshape)
library(gridExtra)
Read in tumor object
# rm(list=ls())
dir <- "/myVolume/scell_lung_adenocarcinoma/"
load(file = paste(dir, "Data_input/NI04_tumor_seurat_object.RData", sep = ""))
Seurat Function for IPA Analysis
seurat.to.ipa <- function(df, score.column, divide.by.column, gene.column, divide.append) {
# Find appropriate columns in DE output
col.1 <- which(colnames(df)==divide.by.column)
col.2 <- which(colnames(df)==score.column)
col.3 <- which(colnames(df)==gene.column)
# Create new table
tab.temp <- matrix(nrow=length(unique(df[,col.3])), ncol=length(unique(df[,col.1])), 0)
# Set colnames
colnames(tab.temp) <- unique(df[,col.1])
# Set townames
row.names(tab.temp) <- as.character(unique(df[,col.3]))
# Populate values
for(i in 1:nrow(tab.temp)){
temp <- df[as.character(df[,col.3]) %in% row.names(tab.temp)[i] ,]
for(j in 1:nrow(temp)){
col.to <- which(colnames(tab.temp)==as.character(temp[j,col.1]))
tab.temp[i,col.to] <- temp[j,col.2]
}
}
# Set colnames
colnames(tab.temp) <- paste(divide.append, colnames(tab.temp), sep="_")
return(tab.temp)
}
Calculate the DE genes for every tumor cluster
Calculate the DE genes between different treatment responses (naive, grouped_pr and grouped_pd)
Top PD genes breakdown
pd.plot.lists.ridge.pt
$GPR87
$KYNU
$LY6K
$UBD
$FHL2
$IGFBP3
$DKK1
$ARNTL2
$CRABP2
$FAM83A
$GJB3
$RGS10
$IDO1
$COMTD1
$CBLC
$UCK2
$GJB2
$PLAU
$PROM2
$GPC1




















Top PR DE Genes breakdown
pr.plot.lists.ridge.pt
$SUSD2
$MS4A15
$SFTPB
$AQP4
$SFTPD
$NAPSA
$RGS16
$C16orf89
$TNS1
$CYP4B1
$C4BPA
$`NKX2-1`
$DLC1
$SCGB3A1
$FLRT3
$ADGRF5
$SFTA3
$RNASE1
$NFIX
$AQP1




















Top Naive DE Genes breakdown
naive.plot.lists.ridge.pt
$CHL1
$CRABP2
$ASS1
$TFF3
$TMSB10
$CAPG
$LY6K
$ALDOA
$IQGAP2
$DMKN
$FXYD5
$C5orf49
$LDHB
$NGFRAP1
$GPR87
$CAV2
$UBD
$TAP1
$CRLF1
$IGFBP5
$GGT5
$TNC
$PGD
$SPAG6
$PPIA
$`HLA-F`
$ARPC2
$IDO1
$VIM
$MUC5B
$SLC27A2
$RRAD
$FOXJ1
$LOC100506844
$`WDR86-AS1`
$KYNU
$FXYD3
$BLVRB
$PSMB9
$DTX3
$AVPI1
$QPRT
$TMBIM1
$CXCL16
$PTP4A2
$DKK1
$TACSTD2
$CPM
$TUBA1A
$NENF


















































Create a Heatmap of the top 20 genes from each reponse group
pdf(file = paste(dir, "plot_out/NI07/NI07_top20_DEgenes_per_group.pdf", sep=""))
DoHeatmap(tiss_subset_tumor, genes.use = top_20$gene, slim.col.label = TRUE, use.scaled = FALSE, group.order = c("naive", "grouped_pr", "grouped_pd"))
dev.off()
null device
1
Begin IPA Analysis
# load Seurat Function for IPA Analysis
source(file = paste(dir, "/scripts/seurat_to_IPA.R", sep = ""))
# filter the indiviudal lists to only include genes with >= 1 average log fold change
markers.pd.1.1 <- filter(markers.pd.1, avg_logFC >= 1)
markers.pr.1.1 <- filter(markers.pr.1, avg_logFC >= 1)
markers.naive.1.1 <- filter(markers.naive.1, avg_logFC >= 1)
# combine all filtered lists into one
all_markers_sorted <- rbind(markers.pd.1.1, markers.pr.1.1, markers.naive.1.1)
# Format analysis markers for IPA
analysis_markers_ipa <- seurat.to.ipa(df = all_markers_sorted, score.column = "avg_logFC", divide.by.column = "cluster", gene.column = "gene", divide.append = "NI07")
# analysis_markers_ipa <- as.data.frame(analysis_markers_ipa)
write.table(analysis_markers_ipa, file = paste(dir, "data_out/NI07/NI07_analysis_markers_for_ipa.txt", sep = ""), row.names = T, quote=F, sep="\t")
Calculate the Sig of GOIs between the Three Groups
LS0tCnRpdGxlOiAiREUgQW5hbHlzaXMgYnkgUmVzcG9uc2UiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyfQpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShmZ3NlYSkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoZGV2dG9vbHMpCmxpYnJhcnkoRFQpCnJlcXVpcmUoY29ycnBsb3QpCmxpYnJhcnkoY2x1c3RyZWUpCmxpYnJhcnkoZ2dzaWduaWYpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KGdncmlkZ2VzKQpsaWJyYXJ5KHJlc2hhcGUpCmxpYnJhcnkoZ3JpZEV4dHJhKQpgYGAKClJlYWQgaW4gdHVtb3Igb2JqZWN0CmBgYHtyfQojIHJtKGxpc3Q9bHMoKSkKZGlyIDwtICIvbXlWb2x1bWUvc2NlbGxfbHVuZ19hZGVub2NhcmNpbm9tYS8iCmxvYWQoZmlsZSA9IHBhc3RlKGRpciwgIkRhdGFfaW5wdXQvTkkwNF90dW1vcl9zZXVyYXRfb2JqZWN0LlJEYXRhIiwgc2VwID0gIiIpKQpgYGAKClNldXJhdCBGdW5jdGlvbiBmb3IgSVBBIEFuYWx5c2lzCmBgYHtyfQpzZXVyYXQudG8uaXBhIDwtIGZ1bmN0aW9uKGRmLCBzY29yZS5jb2x1bW4sIGRpdmlkZS5ieS5jb2x1bW4sIGdlbmUuY29sdW1uLCBkaXZpZGUuYXBwZW5kKSB7CiAgIyBGaW5kIGFwcHJvcHJpYXRlIGNvbHVtbnMgaW4gREUgb3V0cHV0IAogIGNvbC4xIDwtIHdoaWNoKGNvbG5hbWVzKGRmKT09ZGl2aWRlLmJ5LmNvbHVtbikKICBjb2wuMiA8LSB3aGljaChjb2xuYW1lcyhkZik9PXNjb3JlLmNvbHVtbikKICBjb2wuMyA8LSB3aGljaChjb2xuYW1lcyhkZik9PWdlbmUuY29sdW1uKQogICMgQ3JlYXRlIG5ldyB0YWJsZQogIHRhYi50ZW1wIDwtIG1hdHJpeChucm93PWxlbmd0aCh1bmlxdWUoZGZbLGNvbC4zXSkpLCBuY29sPWxlbmd0aCh1bmlxdWUoZGZbLGNvbC4xXSkpLCAwKQogICMgU2V0IGNvbG5hbWVzIAogIGNvbG5hbWVzKHRhYi50ZW1wKSA8LSB1bmlxdWUoZGZbLGNvbC4xXSkKICAjIFNldCB0b3duYW1lcyAKICByb3cubmFtZXModGFiLnRlbXApIDwtIGFzLmNoYXJhY3Rlcih1bmlxdWUoZGZbLGNvbC4zXSkpCiAgIyBQb3B1bGF0ZSB2YWx1ZXMgCiAgICBmb3IoaSBpbiAxOm5yb3codGFiLnRlbXApKXsKICAgICAgdGVtcCA8LSBkZlthcy5jaGFyYWN0ZXIoZGZbLGNvbC4zXSkgJWluJSByb3cubmFtZXModGFiLnRlbXApW2ldICxdCiAgICAgICAgZm9yKGogaW4gMTpucm93KHRlbXApKXsKICAgICAgICAgIGNvbC50byA8LSB3aGljaChjb2xuYW1lcyh0YWIudGVtcCk9PWFzLmNoYXJhY3Rlcih0ZW1wW2osY29sLjFdKSkKICAgICAgICAgIHRhYi50ZW1wW2ksY29sLnRvXSA8LSB0ZW1wW2osY29sLjJdCiAgICAgICAgfQogICAgfQogICMgU2V0IGNvbG5hbWVzIAogIGNvbG5hbWVzKHRhYi50ZW1wKSA8LSBwYXN0ZShkaXZpZGUuYXBwZW5kLCBjb2xuYW1lcyh0YWIudGVtcCksIHNlcD0iXyIpCiAgcmV0dXJuKHRhYi50ZW1wKQp9CmBgYAoKQ2FsY3VsYXRlIHRoZSBERSBnZW5lcyBmb3IgZXZlcnkgdHVtb3IgY2x1c3RlcgpgYGB7cn0KZGVfYnlfY2x1c3RlciA8LSBGaW5kQWxsTWFya2Vycyh0aXNzX3N1YnNldF90dW1vcikKd3JpdGUuY3N2KGRlX2J5X2NsdXN0ZXIsIGZpbGUgPSBwYXN0ZShkaXIsICJkYXRhX291dC9OSTA3L05JMDdfdHVtb3JfY2x1c3RlcnNfREVnZW5lcy5jc3YiLCBzZXAgPSAiIikpCmBgYAoKQ2FsY3VsYXRlIHRoZSBERSBnZW5lcyBiZXR3ZWVuIGRpZmZlcmVudCB0cmVhdG1lbnQgcmVzcG9uc2VzIChuYWl2ZSwgZ3JvdXBlZF9wciBhbmQgZ3JvdXBlZF9wZCkKYGBge3J9CiMgc2V0IHRoZSBpZGVudCBvZiB0aGUgb2JqZWN0IHRvIHRoZSAiYW5hbHlzaXMiIGNvbHVtbgp1bmlxdWUodGlzc19zdWJzZXRfdHVtb3JAaWRlbnQpICMgY2hlY2sgY3VycmVudCBpZGVudAp0aXNzX3N1YnNldF90dW1vciA8LSBTZXRJZGVudCh0aXNzX3N1YnNldF90dW1vciwgaWRlbnQudXNlID0gdGlzc19zdWJzZXRfdHVtb3JAbWV0YS5kYXRhJGFuYWx5c2lzKQp1bmlxdWUodGlzc19zdWJzZXRfdHVtb3JAaWRlbnQpICMgY2hlY2sgY3VycmVudCBpZGVudAoKIyBmaW5kIGRpZmYuIGV4cHJlc3NlZCBnZW5lcyB3aXRoIHdpbGNveCB0ZXN0CmFuYWx5c2lzX21hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnModGlzc19zdWJzZXRfdHVtb3IpCndyaXRlLmNzdihhbmFseXNpc19tYXJrZXJzLCBmaWxlID0gcGFzdGUoZGlyLCAiZGF0YV9vdXQvTkkwNy9OSTA3X3Jlc3BvbnNlX2dyb3VwX0RFZ2VuZXMuY3N2Iiwgc2VwID0gIiIpKQoKIyBHcm91cCB0aGUgREUgZ2VuZXMgYW5kIGFkZCB0aGUgbnVtYmVyIG9mIHBhdGllbnRzIHdpdGggbm9uemVybyBleHByZXNzaW5nIGNlbGxzIGFuZCB0aGUgaGlnaGVzdCBjb250cmlidXRpbmcgcGF0aWVudCdzIG9jY3VwYW5jeQpncm91cHMgPC0gYXMuY2hhcmFjdGVyKHVuaXF1ZShhbmFseXNpc19tYXJrZXJzJGNsdXN0ZXIpKQpmb3IoaSBpbiAxOm5yb3coYW5hbHlzaXNfbWFya2VycykpewogIG1lc3NhZ2UocGFzdGUocm91bmQoaS9ucm93KGFuYWx5c2lzX21hcmtlcnMpLDIpKjEwMCwiJSBvZiBnZW5lcyBjb21wbGV0ZWQiKSkKICBnZW5lIDwtIGFzLmNoYXJhY3RlcihhbmFseXNpc19tYXJrZXJzJGdlbmUpW2ldCiAgZ2VuZS52ZWMgPC0gdGlzc19zdWJzZXRfdHVtb3JAZGF0YVtnZW5lLF0KICAgIGZvcihqIGluIDE6bGVuZ3RoKGdyb3VwcykpewogICAgICBjZWxscyA8LSByb3cubmFtZXModGlzc19zdWJzZXRfdHVtb3JAbWV0YS5kYXRhKVt3aGljaCh0aXNzX3N1YnNldF90dW1vckBtZXRhLmRhdGEkYW5hbHlzaXM9PWdyb3Vwc1tqXSldCiAgICAgIGFsbC5uby56ZXJvLmNlbGxzIDwtIG5hbWVzKHdoaWNoKGdlbmUudmVjW2NlbGxzXSAhPTAgKSkgIyBTZXQgdGhyZXNob2xkCiAgICAgIHRhYi4xIDwtIHRhYmxlKGFzLmNoYXJhY3Rlcih0aXNzX3N1YnNldF90dW1vckBtZXRhLmRhdGFbYWxsLm5vLnplcm8uY2VsbHMsInBhdGllbnRfaWQiXSkpCiAgICAgIGhpZ2gucGF0LnBlciA8LSB0YWIuMVt3aGljaCh0YWIuMT09bWF4KHRhYi4xKSlbMV1dL2xlbmd0aChhbGwubm8uemVyby5jZWxscykKICAgICAgYWxsLnBhdC5sZW5ndGggPC0gbGVuZ3RoKHRhYi4xKQogICAgICBhbmFseXNpc19tYXJrZXJzW2kscGFzdGUoZ3JvdXBzW2pdLCJwdC5vY2N1cGFuY3kiKV0gPC0gaGlnaC5wYXQucGVyCiAgICAgIGFuYWx5c2lzX21hcmtlcnNbaSxwYXN0ZShncm91cHNbal0sIm4ubm9uemVyby5wdHMiKV0gPC0gYWxsLnBhdC5sZW5ndGgKICAgIH0KfQp3cml0ZS5jc3YoYW5hbHlzaXNfbWFya2VycywgZmlsZSA9IHBhc3RlKGRpciwgImRhdGFfb3V0L05JMDcvTkkwN19yZXNwb25zZV9ncm91cF9ERWdlbmVzX3dpdGhfcHRfb2NjLmNzdiIsIHNlcCA9ICIiKSkKCiMgQnJlYWsgREUgZ2VuZXMgaW50byBhbmFseXNpcyBncm91cHMKbWFya2Vycy5wZCA8LSBmaWx0ZXIoYW5hbHlzaXNfbWFya2VycywgY2x1c3RlciA9PSAiZ3JvdXBlZF9wZCIgJiBgZ3JvdXBlZF9wZCBwdC5vY2N1cGFuY3lgIDwgLjgwKSAKbWFya2Vycy5wciA8LSBmaWx0ZXIoYW5hbHlzaXNfbWFya2VycywgY2x1c3RlciA9PSAiZ3JvdXBlZF9wciIgJiBgZ3JvdXBlZF9wciBwdC5vY2N1cGFuY3lgIDwgLjgwKSAKbWFya2Vycy5uYWl2ZSA8LSBmaWx0ZXIoYW5hbHlzaXNfbWFya2VycywgY2x1c3RlciA9PSAibmFpdmUiICYgYG5haXZlIHB0Lm9jY3VwYW5jeWAgPCAuODApIAoKd3JpdGUuY3N2KG1hcmtlcnMucGQsIGZpbGUgPSBwYXN0ZShkaXIsICJkYXRhX291dC9OSTA3L05JMDdfcmVzcG9uc2VfZ3JvdXBfREVnZW5lc19wZC5jc3YiLCBzZXAgPSAiIikpCndyaXRlLmNzdihtYXJrZXJzLnByLCBmaWxlID0gcGFzdGUoZGlyLCAiZGF0YV9vdXQvTkkwNy9OSTA3X3Jlc3BvbnNlX2dyb3VwX0RFZ2VuZXNfcHIuY3N2Iiwgc2VwID0gIiIpKQp3cml0ZS5jc3YobWFya2Vycy5uYWl2ZSwgZmlsZSA9IHBhc3RlKGRpciwgImRhdGFfb3V0L05JMDcvTkkwN19yZXNwb25zZV9ncm91cF9ERWdlbmVzX25haXZlLmNzdiIsIHNlcCA9ICIiKSkKYGBgCgpUb3AgUEQgZ2VuZXMgYnJlYWtkb3duCmBgYHtyfQojIGJyZWFrIGRvd24gdG8gdG9wIDIwIHNvcnRlZCBieSBwY3RfZGlmZgptYXJrZXJzLnBkLjEgPC0gbWFya2Vycy5wZAptYXJrZXJzLnBkLjEkcGN0X2RpZmYgPC0gbWFya2Vycy5wZC4xJHBjdC4xIC0gbWFya2Vycy5wZC4xJHBjdC4yCm1hcmtlcnMucGQuMSRwY3RfZGlmZiA8LSBhcy5udW1lcmljKG1hcmtlcnMucGQuMSRwY3RfZGlmZikKbWFya2Vycy5wZC4xIDwtIG1hcmtlcnMucGQuMVtvcmRlcihtYXJrZXJzLnBkLjEkcGN0X2RpZmYsIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQp0b3BfMjBfcGQgPC0gdG9wX24oeCA9IG1hcmtlcnMucGQuMSwgbiA9IDIwLCB3dCA9IHBjdF9kaWZmKQoKcGQuZGUuZ2VuZXMgPC0gRmV0Y2hEYXRhKHRpc3Nfc3Vic2V0X3R1bW9yLCBjKHRvcF8yMF9wZCRnZW5lLCAnbkdlbmUnLCduUmVhZHMnLCdhbmFseXNpcycsJ3BhdGllbnRfaWQnLCAnc2FtcGxlX25hbWUnLCAnYmlvcHN5X3NpdGUnLCAncGZzX292ZXJfdW5kZXInKSkKY29sbmFtZXModGlzc19zdWJzZXRfdHVtb3JAbWV0YS5kYXRhKQpwZC5kZS5nZW5lczEgPC0gY29sbmFtZXMocGQuZGUuZ2VuZXMpW2MoMToyMCldCnRlbXAgPC0gcGQuZGUuZ2VuZXNbLGMoZ3JlcCgibkdlbmUiLCBjb2xuYW1lcyhwZC5kZS5nZW5lcykpOm5jb2wocGQuZGUuZ2VuZXMpKV0KCiMgUGxvdCBqaXR0ZXIgcGxvdCBvZiBQRCB2cyBQUiB2cyBuYWl2ZSBmb3IgdG9wIDUwIERFIGdlbmVzCnBkLnBsb3QubGlzdHMuYm94IDwtIGxpc3QoKQpmb3IoaSBpbiBwZC5kZS5nZW5lczEpewogIGEgPC0gYXMuZGF0YS5mcmFtZShwZC5kZS5nZW5lc1ssaV0pCiAgY29sbmFtZXMoYSkgPC0gImdlbmUiCiAgdGVtcC4xIDwtIGNiaW5kKGEsIHRlbXApIDsgcm0oYSkKICBwZC5wbG90Lmxpc3RzLmJveFtbaV1dIDwtIGdncGxvdCh0ZW1wLjEsIGFlcyh4ID0gYW5hbHlzaXMsIHkgPSBnZW5lLCBjb2xvdXIgPSBhbmFseXNpcykpICsgZ2VvbV9ib3hwbG90KGNvbG9yID0gImJsYWNrIiwgb3V0bGllci5zaGFwZSA9IE5VTEwpICsgZ2VvbV9qaXR0ZXIocG9zaXRpb249cG9zaXRpb25faml0dGVyKDAuMiksIGFscGhhID0gMS80KSArIGdndGl0bGUoaSkKfQoKIyBQbG90IGppdHRlciBwbG90L2JveHBsb3Qgb2YgUEQgdnMgUFIgdnMgbmFpdmUgZm9yIHRvcCA1MCBERSBnZW5lcyBieSBwYXRpZW50CnBkLnBsb3QubGlzdHMucHQuYm94IDwtIGxpc3QoKQpmb3IoaSBpbiBwZC5kZS5nZW5lczEpewogIGEgPC0gYXMuZGF0YS5mcmFtZShwZC5kZS5nZW5lc1ssaV0pCiAgY29sbmFtZXMoYSkgPC0gImdlbmUiCiAgdGVtcC4yIDwtIGNiaW5kKGEsIHRlbXApIDsgcm0oYSkKICBwZC5wbG90Lmxpc3RzLnB0LmJveFtbaV1dIDwtIGdncGxvdCh0ZW1wLjIsIGFlcyh4ID0gYW5hbHlzaXMsIHkgPSBnZW5lLCBjb2xvciA9IHBhdGllbnRfaWQsIGZpbGwgPSBwYXRpZW50X2lkKSkgICsgCiAgICAgIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZShkb2RnZS53aWR0aD0wLjkpKSArCiAgICAgIGdlb21fYm94cGxvdChmaWxsID0gIndoaXRlIiwgb3V0bGllci5jb2xvdXIgPSBOQSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpKSArCiAgICAgIHhsYWIoIkdyb3VwIikgKwogICAgICB5bGFiKHBhc3RlKGksIkdlbmUgRXhwcmVzc2lvbiIpKSArCiAgICAgIGd1aWRlcyhjb2xvdXIgPSBGQUxTRSkgKwogICAgICBndWlkZXMoZmlsbCA9IEZBTFNFKSArIAogICAgICBnZ3RpdGxlKGkpCn0KCiMgUGxvdCByaWRnZSBwbG90IG9mIFBEIHZzIFBSIHZzIG5haXZlIGZvciB0b3AgNTAgREUgZ2VuZXMKcGQucGxvdC5saXN0cy5yaWRnZSA8LSBsaXN0KCkKZm9yKGkgaW4gcGQuZGUuZ2VuZXMxKXsKICBhIDwtIGFzLmRhdGEuZnJhbWUocGQuZGUuZ2VuZXNbLGldKQogIGNvbG5hbWVzKGEpIDwtICJnZW5lIgogIHRlbXAuMyA8LSBjYmluZChhLCB0ZW1wKSA7IHJtKGEpCiAgcGQucGxvdC5saXN0cy5yaWRnZVtbaV1dIDwtIGdncGxvdCh0ZW1wLjMsIGFlcyh4ID0gZ2VuZSwgeSA9IGFuYWx5c2lzLCBmaWxsID0gYW5hbHlzaXMpKSArIGdlb21fZGVuc2l0eV9yaWRnZXMoKSArIHlsYWIoIkdyb3VwIikgKyB4bGFiKHBhc3RlKGksIkdlbmUgRXhwcmVzc2lvbiIpKSArIGdndGl0bGUocGFzdGUoaSwiRXhwcmVzc2lvbiBwZXIgR3JvdXAiKSkgKyBndWlkZXMoY29sb3VyID0gRkFMU0UsIGZpbGwgPSBGQUxTRSkKfQoKIyBQbG90IHJpZGdlIHBsb3Qgb2YgUEQgdnMgUFIgdnMgbmFpdmUgZm9yIHRvcCA1MCBERSBnZW5lcyBieSBwYXRpZW50CnBkLnBsb3QubGlzdHMucmlkZ2UucHQgPC0gbGlzdCgpCmZvcihpIGluIHBkLmRlLmdlbmVzMSl7CiAgYSA8LSBhcy5kYXRhLmZyYW1lKHBkLmRlLmdlbmVzWyxpXSkKICBjb2xuYW1lcyhhKSA8LSAiZ2VuZSIKICB0ZW1wLjQgPC0gY2JpbmQoYSwgdGVtcCkgOyBybShhKQogIHBkLnBsb3QubGlzdHMucmlkZ2UucHRbW2ldXSA8LSBnZ3Bsb3QodGVtcC40LCBhZXMoeCA9IGdlbmUsIHkgPSBhbmFseXNpcywgZmlsbCA9IHBhdGllbnRfaWQpKSArIGdlb21fZGVuc2l0eV9yaWRnZXMoYWxwaGE9MS8yKSArIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyB4bGFiKHBhc3RlKGksIkdlbmUgRXhwcmVzc2lvbiIpKSArIGd1aWRlcyhjb2xvdXIgPSBGQUxTRSwgZmlsbCA9IEZBTFNFKSArIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gYygiUHJvZ3Jlc3NvciIsICJQcmVzaXN0ZXIiLCAiTmFpdmUiKSkKfQoKIyBzYXZlIGJ5IHBhdGllbnQgcmlkZ2VwbG90cwpwZGYoZmlsZSA9IHBhc3RlKGRpciwgInBsb3Rfb3V0L05JMDcvTkkwN19wZF9yaWRlcGxvdHNfYnlfcGF0aWVudC5wZGYiLCBzZXAgPSAiIiksIG9uZWZpbGUgPSBUUlVFKQptYXJyYW5nZUdyb2IoZ3JvYnM9cGQucGxvdC5saXN0cy5yaWRnZS5wdCwgbnJvdz0xLCBuY29sPTEpCmRldi5vZmYoKQoKYGBgCgpUb3AgUFIgREUgR2VuZXMgYnJlYWtkb3duCmBgYHtyfQojIGJyZWFrIGRvd24gdG8gdG9wIDIwIHNvcnRlZCBieSBwY3RfZGlmZgptYXJrZXJzLnByLjEgPC0gbWFya2Vycy5wcgptYXJrZXJzLnByLjEkcGN0X2RpZmYgPC0gbWFya2Vycy5wci4xJHBjdC4xIC0gbWFya2Vycy5wci4xJHBjdC4yCm1hcmtlcnMucHIuMSRwY3RfZGlmZiA8LSBhcy5udW1lcmljKG1hcmtlcnMucHIuMSRwY3RfZGlmZikKbWFya2Vycy5wci4xIDwtIG1hcmtlcnMucHIuMVtvcmRlcihtYXJrZXJzLnByLjEkcGN0X2RpZmYsIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQp0b3BfMjBfcHIgPC0gdG9wX24oeCA9IG1hcmtlcnMucHIuMSwgbiA9IDIwLCB3dCA9IHBjdF9kaWZmKQoKcHIuZGUuZ2VuZXMgPC0gRmV0Y2hEYXRhKHRpc3Nfc3Vic2V0X3R1bW9yLCBjKHRvcF8yMF9wciRnZW5lLCAnbkdlbmUnLCduUmVhZHMnLCdhbmFseXNpcycsJ3BhdGllbnRfaWQnLCAnc2FtcGxlX25hbWUnLCAnYmlvcHN5X3NpdGUnKSkKCnByLmRlLmdlbmVzMSA8LSBjb2xuYW1lcyhwci5kZS5nZW5lcylbYygxOjIwKV0KdGVtcCA8LSBwci5kZS5nZW5lc1ssYyhncmVwKCJuR2VuZSIsIGNvbG5hbWVzKHByLmRlLmdlbmVzKSk6bmNvbChwci5kZS5nZW5lcykpXQoKCiMgUGxvdCBqaXR0ZXIgcGxvdCBvZiBwciB2cyBQUiB2cyBuYWl2ZSBmb3IgdG9wIDUwIERFIGdlbmVzCnByLnBsb3QubGlzdHMuYm94IDwtIGxpc3QoKQpmb3IoaSBpbiBwci5kZS5nZW5lczEpewogIGEgPC0gYXMuZGF0YS5mcmFtZShwci5kZS5nZW5lc1ssaV0pCiAgY29sbmFtZXMoYSkgPC0gImdlbmUiCiAgdGVtcC4xIDwtIGNiaW5kKGEsIHRlbXApIDsgcm0oYSkKICBwci5wbG90Lmxpc3RzLmJveFtbaV1dIDwtIGdncGxvdCh0ZW1wLjEsIGFlcyh4ID0gYW5hbHlzaXMsIHkgPSBnZW5lLCBmaWxsID0gYW5hbHlzaXMpKSArIGdlb21faml0dGVyKGFlcyhjb2xvdXIgPSBhbmFseXNpcyksIGFscGhhID0gMS80KSArIGdndGl0bGUoaSkKfQoKIyBQbG90IGppdHRlciBwbG90L2JveHBsb3Qgb2YgcHIgdnMgUFIgdnMgbmFpdmUgZm9yIHRvcCA1MCBERSBnZW5lcyBieSBwYXRpZW50CnByLnBsb3QubGlzdHMucHQuYm94IDwtIGxpc3QoKQpmb3IoaSBpbiBwci5kZS5nZW5lczEpewogIGEgPC0gYXMuZGF0YS5mcmFtZShwci5kZS5nZW5lc1ssaV0pCiAgY29sbmFtZXMoYSkgPC0gImdlbmUiCiAgdGVtcC4yIDwtIGNiaW5kKGEsIHRlbXApIDsgcm0oYSkKICBwci5wbG90Lmxpc3RzLnB0LmJveFtbaV1dIDwtIGdncGxvdCh0ZW1wLjIsIGFlcyh4ID0gYW5hbHlzaXMsIHkgPSBnZW5lLCBjb2xvciA9IHBhdGllbnRfaWQsIGZpbGwgPSBwYXRpZW50X2lkKSkgICsgCiAgICAgIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXJkb2RnZShkb2RnZS53aWR0aD0wLjkpKSArCiAgICAgIGdlb21fYm94cGxvdChmaWxsID0gIndoaXRlIiwgb3V0bGllci5jb2xvdXIgPSBOQSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpKSArCiAgICAgIHhsYWIoIkdyb3VwIikgKwogICAgICB5bGFiKHBhc3RlKGksIkdlbmUgRXhwcmVzc2lvbiIpKSArCiAgICAgIGd1aWRlcyhjb2xvdXIgPSBGQUxTRSkgKwogICAgICBndWlkZXMoZmlsbCA9IEZBTFNFKSArIAogICAgICBnZ3RpdGxlKGkpCn0KCiMgUGxvdCByaWRnZSBwbG90IG9mIHByIHZzIFBSIHZzIG5haXZlIGZvciB0b3AgNTAgREUgZ2VuZXMKcHIucGxvdC5saXN0cy5yaWRnZSA8LSBsaXN0KCkKZm9yKGkgaW4gcHIuZGUuZ2VuZXMxKXsKICBhIDwtIGFzLmRhdGEuZnJhbWUocHIuZGUuZ2VuZXNbLGldKQogIGNvbG5hbWVzKGEpIDwtICJnZW5lIgogIHRlbXAuMyA8LSBjYmluZChhLCB0ZW1wKSA7IHJtKGEpCiAgcHIucGxvdC5saXN0cy5yaWRnZVtbaV1dIDwtIGdncGxvdCh0ZW1wLjMsIGFlcyh4ID0gZ2VuZSwgeSA9IGFuYWx5c2lzLCBmaWxsID0gYW5hbHlzaXMpKSArIGdlb21fZGVuc2l0eV9yaWRnZXMoKSArIHlsYWIoIkdyb3VwIikgKyB4bGFiKHBhc3RlKGksIkdlbmUgRXhwcmVzc2lvbiIpKSArIGdndGl0bGUocGFzdGUoaSwiRXhwcmVzc2lvbiBwZXIgR3JvdXAiKSkgKyBndWlkZXMoY29sb3VyID0gRkFMU0UsIGZpbGwgPSBGQUxTRSkKfQoKIyBQbG90IHJpZGdlIHBsb3Qgb2YgcHIgdnMgUFIgdnMgbmFpdmUgZm9yIHRvcCA1MCBERSBnZW5lcyBieSBwYXRpZW50CnByLnBsb3QubGlzdHMucmlkZ2UucHQgPC0gbGlzdCgpCmZvcihpIGluIHByLmRlLmdlbmVzMSl7CiAgYSA8LSBhcy5kYXRhLmZyYW1lKHByLmRlLmdlbmVzWyxpXSkKICBjb2xuYW1lcyhhKSA8LSAiZ2VuZSIKICB0ZW1wLjQgPC0gY2JpbmQoYSwgdGVtcCkgOyBybShhKQogIHByLnBsb3QubGlzdHMucmlkZ2UucHRbW2ldXSA8LSBnZ3Bsb3QodGVtcC40LCBhZXMoeCA9IGdlbmUsIHkgPSBhbmFseXNpcywgZmlsbCA9IHBhdGllbnRfaWQpKSArIGdlb21fZGVuc2l0eV9yaWRnZXMoYWxwaGE9MS8yKSArIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyB4bGFiKHBhc3RlKGksIkdlbmUgRXhwcmVzc2lvbiIpKSArIGd1aWRlcyhjb2xvdXIgPSBGQUxTRSwgZmlsbCA9IEZBTFNFKSArIHNjYWxlX3lfZGlzY3JldGUobGFiZWxzID0gYygiUHJvZ3Jlc3NvciIsICJQcmVzaXN0ZXIiLCAiTmFpdmUiKSkKfQoKIyBzYXZlIGJ5IHBhdGllbnQgcmlkZ2VwbG90cwpwZGYoZmlsZSA9IHBhc3RlKGRpciwgInBsb3Rfb3V0L05JMDcvTkkwN19wcl9yaWRlcGxvdHNfYnlfcGF0aWVudC5wZGYiLCBzZXAgPSAiIiksIG9uZWZpbGUgPSBUUlVFKQptYXJyYW5nZUdyb2IoZ3JvYnM9cHIucGxvdC5saXN0cy5yaWRnZS5wdCwgbnJvdz0xLCBuY29sPTEpCmRldi5vZmYoKQpgYGAKClRvcCBOYWl2ZSBERSBHZW5lcyBicmVha2Rvd24KYGBge3J9CgojIGJyZWFrIGRvd24gdG8gdG9wIDIwIHNvcnRlZCBieSBwY3RfZGlmZgptYXJrZXJzLm5haXZlLjEgPC0gbWFya2Vycy5uYWl2ZQptYXJrZXJzLm5haXZlLjEkcGN0X2RpZmYgPC0gbWFya2Vycy5uYWl2ZS4xJHBjdC4xIC0gbWFya2Vycy5uYWl2ZS4xJHBjdC4yCm1hcmtlcnMubmFpdmUuMSRwY3RfZGlmZiA8LSBhcy5udW1lcmljKG1hcmtlcnMubmFpdmUuMSRwY3RfZGlmZikKbWFya2Vycy5uYWl2ZS4xIDwtIG1hcmtlcnMubmFpdmUuMVtvcmRlcihtYXJrZXJzLm5haXZlLjEkcGN0X2RpZmYsIGRlY3JlYXNpbmcgPSBUUlVFKSwgXQp0b3BfMjBfbmFpdmUgPC0gdG9wX24oeCA9IG1hcmtlcnMubmFpdmUuMSwgbiA9IDIwLCB3dCA9IHBjdF9kaWZmKQoKbmFpdmUuZGUuZ2VuZXMgPC0gRmV0Y2hEYXRhKHRpc3Nfc3Vic2V0X3R1bW9yLCBjKHRvcF8yMF9uYWl2ZSwgJ25HZW5lJywnblJlYWRzJywnYW5hbHlzaXMnLCdwYXRpZW50X2lkJywgJ3NhbXBsZV9uYW1lJywgJ2Jpb3BzeV9zaXRlJykpCgpuYWl2ZS5kZS5nZW5lczEgPC0gY29sbmFtZXMobmFpdmUuZGUuZ2VuZXMpW2MoMTo1MCldCnRlbXAgPC0gbmFpdmUuZGUuZ2VuZXNbLGMoZ3JlcCgibkdlbmUiLCBjb2xuYW1lcyhuYWl2ZS5kZS5nZW5lcykpOm5jb2wobmFpdmUuZGUuZ2VuZXMpKV0KCgojIFBsb3Qgaml0dGVyIHBsb3Qgb2YgbmFpdmUgdnMgbmFpdmUgdnMgbmFpdmUgZm9yIHRvcCA1MCBERSBnZW5lcwpuYWl2ZS5wbG90Lmxpc3RzLmJveCA8LSBsaXN0KCkKZm9yKGkgaW4gbmFpdmUuZGUuZ2VuZXMxKXsKICBhIDwtIGFzLmRhdGEuZnJhbWUobmFpdmUuZGUuZ2VuZXNbLGldKQogIGNvbG5hbWVzKGEpIDwtICJnZW5lIgogIHRlbXAuMSA8LSBjYmluZChhLCB0ZW1wKSA7IHJtKGEpCiAgbmFpdmUucGxvdC5saXN0cy5ib3hbW2ldXSA8LSBnZ3Bsb3QodGVtcC4xLCBhZXMoeCA9IGFuYWx5c2lzLCB5ID0gZ2VuZSwgZmlsbCA9IGFuYWx5c2lzKSkgKyBnZW9tX2ppdHRlcihhZXMoY29sb3VyID0gYW5hbHlzaXMpLCBhbHBoYSA9IDEvNCkgKyBnZ3RpdGxlKGkpCn0KCiMgUGxvdCBqaXR0ZXIgcGxvdC9ib3hwbG90IG9mIG5haXZlIHZzIG5haXZlIHZzIG5haXZlIGZvciB0b3AgNTAgREUgZ2VuZXMgYnkgcGF0aWVudApuYWl2ZS5wbG90Lmxpc3RzLnB0LmJveCA8LSBsaXN0KCkKZm9yKGkgaW4gbmFpdmUuZGUuZ2VuZXMxKXsKICBhIDwtIGFzLmRhdGEuZnJhbWUobmFpdmUuZGUuZ2VuZXNbLGldKQogIGNvbG5hbWVzKGEpIDwtICJnZW5lIgogIHRlbXAuMiA8LSBjYmluZChhLCB0ZW1wKSA7IHJtKGEpCiAgbmFpdmUucGxvdC5saXN0cy5wdC5ib3hbW2ldXSA8LSBnZ3Bsb3QodGVtcC4yLCBhZXMoeCA9IGFuYWx5c2lzLCB5ID0gZ2VuZSwgY29sb3IgPSBwYXRpZW50X2lkLCBmaWxsID0gcGF0aWVudF9pZCkpICArIAogICAgICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2UoZG9kZ2Uud2lkdGg9MC45KSkgKwogICAgICBnZW9tX2JveHBsb3QoZmlsbCA9ICJ3aGl0ZSIsIG91dGxpZXIuY29sb3VyID0gTkEsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGg9MC45KSkgKwogICAgICB4bGFiKCJHcm91cCIpICsKICAgICAgeWxhYihwYXN0ZShpLCJHZW5lIEV4cHJlc3Npb24iKSkgKwogICAgICBndWlkZXMoY29sb3VyID0gRkFMU0UpICsKICAgICAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkgKyAKICAgICAgZ2d0aXRsZShpKQp9CgojIFBsb3QgcmlkZ2UgcGxvdCBvZiBuYWl2ZSB2cyBuYWl2ZSB2cyBuYWl2ZSBmb3IgdG9wIDUwIERFIGdlbmVzCm5haXZlLnBsb3QubGlzdHMucmlkZ2UgPC0gbGlzdCgpCmZvcihpIGluIG5haXZlLmRlLmdlbmVzMSl7CiAgYSA8LSBhcy5kYXRhLmZyYW1lKG5haXZlLmRlLmdlbmVzWyxpXSkKICBjb2xuYW1lcyhhKSA8LSAiZ2VuZSIKICB0ZW1wLjMgPC0gY2JpbmQoYSwgdGVtcCkgOyBybShhKQogIG5haXZlLnBsb3QubGlzdHMucmlkZ2VbW2ldXSA8LSBnZ3Bsb3QodGVtcC4zLCBhZXMoeCA9IGdlbmUsIHkgPSBhbmFseXNpcywgZmlsbCA9IGFuYWx5c2lzKSkgKyBnZW9tX2RlbnNpdHlfcmlkZ2VzKCkgKyB5bGFiKCJHcm91cCIpICsgeGxhYihwYXN0ZShpLCJHZW5lIEV4cHJlc3Npb24iKSkgKyBnZ3RpdGxlKHBhc3RlKGksIkV4cHJlc3Npb24gcGVyIEdyb3VwIikpICsgZ3VpZGVzKGNvbG91ciA9IEZBTFNFLCBmaWxsID0gRkFMU0UpCn0KCiMgUGxvdCByaWRnZSBwbG90IG9mIG5haXZlIHZzIG5haXZlIHZzIG5haXZlIGZvciB0b3AgNTAgREUgZ2VuZXMgYnkgcGF0aWVudApuYWl2ZS5wbG90Lmxpc3RzLnJpZGdlLnB0IDwtIGxpc3QoKQpmb3IoaSBpbiBuYWl2ZS5kZS5nZW5lczEpewogIGEgPC0gYXMuZGF0YS5mcmFtZShuYWl2ZS5kZS5nZW5lc1ssaV0pCiAgY29sbmFtZXMoYSkgPC0gImdlbmUiCiAgdGVtcC40IDwtIGNiaW5kKGEsIHRlbXApIDsgcm0oYSkKICBuYWl2ZS5wbG90Lmxpc3RzLnJpZGdlLnB0W1tpXV0gPC0gZ2dwbG90KHRlbXAuNCwgYWVzKHggPSBnZW5lLCB5ID0gYW5hbHlzaXMsIGZpbGwgPSBwYXRpZW50X2lkKSkgKyBnZW9tX2RlbnNpdHlfcmlkZ2VzKGFscGhhPTEvMikgKyB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsgeGxhYihwYXN0ZShpLCJHZW5lIEV4cHJlc3Npb24iKSkgKyBndWlkZXMoY29sb3VyID0gRkFMU0UsIGZpbGwgPSBGQUxTRSkgKyBzY2FsZV95X2Rpc2NyZXRlKGxhYmVscyA9IGMoIlByb2dyZXNzb3IiLCAiUHJlc2lzdGVyIiwgIk5haXZlIikpCn0KCiMgc2F2ZSBieSBwYXRpZW50IHJpZGdlcGxvdHMKcGRmKGZpbGUgPSBwYXN0ZShkaXIsICJwbG90X291dC9OSTA3L05JMDdfbmFpdmVfcmlkZXBsb3RzX2J5X3BhdGllbnQucGRmIiwgc2VwID0gIiIpLCBvbmVmaWxlID0gVFJVRSkKbWFycmFuZ2VHcm9iKGdyb2JzPW5haXZlLnBsb3QubGlzdHMucmlkZ2UucHQsIG5yb3c9MSwgbmNvbD0xKQpkZXYub2ZmKCkKYGBgCgpDcmVhdGUgYSBIZWF0bWFwIG9mIHRoZSB0b3AgMjAgZ2VuZXMgZnJvbSBlYWNoIHJlcG9uc2UgZ3JvdXAKYGBge3J9CnRvcF8yMCA8LSByYmluZChtYXJrZXJzLnBkLjFbKDE6MjApLCg2OjcpXSwgbWFya2Vycy5wci4xWygxOjIwKSwoNjo3KV0sIG1hcmtlcnMubmFpdmUuMVsoMToyMCksKDY6NyldKQoKdGlzc19zdWJzZXRfdHVtb3IgPC0gU2V0SWRlbnQodGlzc19zdWJzZXRfdHVtb3IsIGlkZW50LnVzZSA9IHRpc3Nfc3Vic2V0X3R1bW9yQG1ldGEuZGF0YSRhbmFseXNpcykKcGRmKGZpbGUgPSBwYXN0ZShkaXIsICJwbG90X291dC9OSTA3L05JMDdfdG9wMjBfREVnZW5lc19wZXJfZ3JvdXAucGRmIiwgc2VwPSIiKSkKRG9IZWF0bWFwKHRpc3Nfc3Vic2V0X3R1bW9yLCBnZW5lcy51c2UgPSB0b3BfMjAkZ2VuZSwgc2xpbS5jb2wubGFiZWwgPSBUUlVFLCB1c2Uuc2NhbGVkID0gRkFMU0UsIGdyb3VwLm9yZGVyID0gYygibmFpdmUiLCAiZ3JvdXBlZF9wciIsICJncm91cGVkX3BkIikpCmRldi5vZmYoKQpgYGAKCkJlZ2luIElQQSBBbmFseXNpcwpgYGB7cn0KIyBsb2FkIFNldXJhdCBGdW5jdGlvbiBmb3IgSVBBIEFuYWx5c2lzCnNvdXJjZShmaWxlID0gcGFzdGUoZGlyLCAiL3NjcmlwdHMvc2V1cmF0X3RvX0lQQS5SIiwgc2VwID0gIiIpKQojIGZpbHRlciB0aGUgaW5kaXZpdWRhbCBsaXN0cyB0byBvbmx5IGluY2x1ZGUgZ2VuZXMgd2l0aCA+PSAxIGF2ZXJhZ2UgbG9nIGZvbGQgY2hhbmdlCm1hcmtlcnMucGQuMS4xIDwtIGZpbHRlcihtYXJrZXJzLnBkLjEsIGF2Z19sb2dGQyA+PSAxKQptYXJrZXJzLnByLjEuMSA8LSBmaWx0ZXIobWFya2Vycy5wci4xLCBhdmdfbG9nRkMgPj0gMSkKbWFya2Vycy5uYWl2ZS4xLjEgPC0gZmlsdGVyKG1hcmtlcnMubmFpdmUuMSwgYXZnX2xvZ0ZDID49IDEpCiMgY29tYmluZSBhbGwgZmlsdGVyZWQgbGlzdHMgaW50byBvbmUKYWxsX21hcmtlcnNfc29ydGVkIDwtIHJiaW5kKG1hcmtlcnMucGQuMS4xLCBtYXJrZXJzLnByLjEuMSwgbWFya2Vycy5uYWl2ZS4xLjEpCiMgRm9ybWF0IGFuYWx5c2lzIG1hcmtlcnMgZm9yIElQQQphbmFseXNpc19tYXJrZXJzX2lwYSA8LSBzZXVyYXQudG8uaXBhKGRmID0gYWxsX21hcmtlcnNfc29ydGVkLCBzY29yZS5jb2x1bW4gPSAiYXZnX2xvZ0ZDIiwgZGl2aWRlLmJ5LmNvbHVtbiA9ICJjbHVzdGVyIiwgZ2VuZS5jb2x1bW4gPSAiZ2VuZSIsIGRpdmlkZS5hcHBlbmQgPSAiTkkwNyIpCiMgYW5hbHlzaXNfbWFya2Vyc19pcGEgPC0gYXMuZGF0YS5mcmFtZShhbmFseXNpc19tYXJrZXJzX2lwYSkKd3JpdGUudGFibGUoYW5hbHlzaXNfbWFya2Vyc19pcGEsIGZpbGUgPSBwYXN0ZShkaXIsICJkYXRhX291dC9OSTA3L05JMDdfYW5hbHlzaXNfbWFya2Vyc19mb3JfaXBhLnR4dCIsIHNlcCA9ICIiKSwgcm93Lm5hbWVzID0gVCwgcXVvdGU9Riwgc2VwPSJcdCIpCmBgYAoKCkNhbGN1bGF0ZSB0aGUgU2lnIG9mIEdPSXMgYmV0d2VlbiB0aGUgVGhyZWUgR3JvdXBzCmBgYHtyfQp0b3BfMjBfZGF0YSA8LSBGZXRjaERhdGEodGlzc19zdWJzZXRfdHVtb3IsIGModG9wXzIwJGdlbmUsICJhbmFseXNpcyIsICJwYXRpZW50X2lkIiwgInNhbXBsZV9uYW1lIikpCgoKIyBjcmVhdGUgZHVtbXkgb3V0cHV0CnRlc3RfZGYgPC0gZGF0YS5mcmFtZShjb2xuYW1lcyh0b3BfMjBfZGF0YSlbMTo2MF0pCnJvd25hbWVzKHRlc3RfZGYpIDwtIHRlc3RfZGYkZ2VuZXMKY29sbmFtZXModGVzdF9kZikgPC0gImdlbmVzIgp0ZXN0X2RmJFBEdnNQUiA8LSAwCnRlc3RfZGYkUER2c05haXZlIDwtIDAKdGVzdF9kZiRQUnZzTmFpdmUgPC0gMAoKZm9yKGkgaW4gMTpuY29sKHRvcF8yMF9kYXRhWywxOjYwXSkpewogIGEgPC0gcGFpcndpc2Uud2lsY294LnRlc3QoeCA9IHRvcF8yMF9kYXRhWyxpXSwgZyA9IHRvcF8yMF9kYXRhJGFuYWx5c2lzKQogIGIgPC0gYXMuZGF0YS5mcmFtZShhJHAudmFsdWUpCiAgdGVzdF9kZltpLDJdIDwtIGJbMSwxXQogIHRlc3RfZGZbaSwzXSA8LSBiWzIsMV0KICB0ZXN0X2RmW2ksNF0gPC0gYlsyLDJdCn0KCnBhaXJ3aXNlLndpbGNveC50ZXN0KHggPSB0b3BfMjBfZGF0YSRUVUJBMUEsIGcgPSB0b3BfMjBfZGF0YSRhbmFseXNpcykKCmBgYAoKCg==